package com.alibaba.nacos.core.remote;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Service
@Slf4j
public class ConnectionManager {
    @Autowired
    private ClientConnectionEventListenerRegistry connectionEventListenerRegistry;

    Map<String, Connection> connections = new ConcurrentHashMap<>() {
        @Override
        public Connection remove(Object key) {
            log.error("remove connection key {} size {}", key, size() - 1);
            return super.remove(key);
        }

        @Override
        public Connection putIfAbsent(String key,
                                      Connection value) {
            log.warn("add connection key {} size {}", key, size() + 1);
            return super.putIfAbsent(key, value);
        }
    };
    private Map<String, AtomicInteger> connectionFroClientIp = new ConcurrentHashMap<>(16);

    public synchronized boolean register(String connectionId,
                                         Connection connection) {
        if (!connection.isConnected()) {
            return false;
        }

        Connection old = connections.putIfAbsent(connectionId, connection);
        if (old != null) {
            return true;
        }

        String clientIp = connection.getMetaInfo().getClientIp();
        connectionFroClientIp.computeIfAbsent(clientIp, k -> new AtomicInteger()).getAndIncrement();
        connectionEventListenerRegistry.notifyClientConnected(connection);
        return true;
    }

    public boolean checkValid(String connectionId) {
        return connections.containsKey(connectionId);
    }

    public Connection getConnection(String connectionId) {
        return connections.get(connectionId);
    }

    public void unregister(String connectionId) {
        Connection remove = connections.remove(connectionId);
        connectionEventListenerRegistry.notifyClientDisConnected(remove);
    }

    public void refreshActiveTime(String connectionId) {
        Optional.ofNullable(connections.get(connectionId)).ifPresent(Connection::freshActiveTime);
    }
}
